package com.css.bjdt_core.executive.util;

import java.util.List;
import java.util.Map;

import com.css.bjdt_core.cell.entity.Cell;
import com.css.bjdt_core.executive.entity.Exp;
import com.css.bjdt_core.executive.entity.IType;
import com.css.bjdt_core.util.CommonUtil;
import com.css.bjdt_core.util.ReportConstant;

/**
 * 
 * 1.前台行计算表达式:1行=2行+3行;前台列计算表达式:A列=B列+C列;前台单元格计算表达式:A1=B1+C1;
 * 2.后台行计算表达式:1行=2行+3行;后台列计算表达式:1列=2列+3列;后台单元格计算表达式:[1_1]=[1_2]+[1_3];
 * 3.前台行校核表达式:1行=2行+3行;前台列校核表达式:A列=B列+C列;前台表内单元格校核表达式:A1=B1+C1;前台表间单元格校核表达式:表1.A1=表2.A2+表3.A3;
 * 4.后台行校核表达式:1行=2行+3行;后台列校核表达式:1列=2列+3列;后台表内表间单元格校核表达式:指标1的id=指标2的id+指标3的id;
 * 5.行或列校核(计算)用相对坐标;单元格计算用绝对坐标;单元格校核用指标id(这块设计的不好,应该涉及到单元格的计算、校核全用指标id)
 * 
 */
public abstract class ExpParser {
	//以计算类型为key
	private Map<String, List<Exp>> expMap;

	/**
	 * 解析计算表达式
	 * @param cell
	 */
	public abstract void parseExp(Cell cell);

	/**
	 * 转换表达式通用方法(现在拆开了，因为报表初始化的时候需要给表外的单元格加cell：这个字符串，但是在报表校核的时候不需要加cell:
	 * 故把报表初始化计算格和报表校核的转化表达式拆开)
	 * @param cell
	 * @param type
	 */
	private void convertExpToCellExp(Cell cell, String type) {
		List<Exp> exps = expMap.get(type);
		if (exps != null && exps.size() > 0) {
			for (Exp exp : exps) {
				String formula = exp.getFormula();
				// 存储原表达式
				cell.setOldExp(formula);
				// 按关系运算符(><=)拆分
				String[] array = formula.split(ReportConstant.OPERATOR_RELA);
				// 判断计算表达式拆分完成后是否为2部分
				if (array.length == 2) {
					// 等号前面部分为计算指标的行号或列号
					String resultNum = getNumber(array[0]);
					// 等号后面部分为参加计算的指标表达式
					String calcExp = array[1];
					// 按算数运算符(+-*/)拆分
					String[] calcNums = calcExp.split(ReportConstant.OPERATOR_ARITH);
					// 如果计算类型为行计算且指标的行号等于计算指标的行号,那么遍历并替换行表达式为单元格表达式
					if (IType.TABLE_INNER_ROW.equals(type) && cell.getRelRowNum() != null
							&& cell.getRelRowNum().toString().equals(resultNum)) {
						for (String calcNum : calcNums) {
							// 替换成:[行号+拆分符+列号]
							StringBuilder key = new StringBuilder();
							key.append("[").append(getNumber(calcNum)).append(ReportConstant.SPLIT_OPERATOR)
									.append(cell.getRelColNum()).append("]");
							calcExp = calcExp.replaceFirst(calcNum, key.toString());
						}
					}
					// 如果计算类型为列计算且指标的列号等于计算指标的列号,那么遍历并替换列表达式为单元格表达式
					else if (IType.TABLE_INNER_COL.equals(type) && cell.getRelColNum() != null
							&& cell.getRelColNum().toString().equals(resultNum)) {
						for (String calcNum : calcNums) {
							StringBuilder key = new StringBuilder();
							key.append("[").append(cell.getRelRowNum()).append(ReportConstant.SPLIT_OPERATOR)
									.append(getNumber(calcNum)).append("]");
							calcExp = calcExp.replaceFirst(calcNum, key.toString());
						}
					}
					// 如果计算类型为单元格计算且指标的行号与列号等于计算指标的行号与列号,那么不做处理
					/*else if (IType.TABLE_INNER_CELL.equals(type) && array[0].equals(
							"[" + cell.getAbsRowNum() + ReportConstant.SPLIT_OPERATOR + cell.getAbsColNum() + "]")) {
						calcExp = "cell:" + calcExp;
					}*/
					else if (IType.TABLE_INNER_CELL.equals(type)) {
						String leftFormula = CommonUtil.coordinateChange(resultNum);
						String[] leftFormulaArray = leftFormula.split(",");
						if (cell.getAbsColNum().toString().equals(leftFormulaArray[0])
								&& cell.getAbsRowNum().toString().equals(leftFormulaArray[1])) {
							String[] coordinateList = calcExp.split(ReportConstant.OPERATOR_ARITH);
							for (String coordinate : coordinateList) {
								String coordinateNew = CommonUtil.coordinateChangeOtherRowCol(coordinate);
								calcExp = calcExp.replaceFirst(coordinate, "[" + coordinateNew + "]");
							}
							calcExp = "cell:" + calcExp;
						} else {
							calcExp = null;
						}
					} else {
						calcExp = null;
					}
					if (calcExp != null) {
						Exp e = cell.getCalcExp();
						e.setCellExp(calcExp);
						e.setFormulaType(exp.getFormulaType());
						e.setFormulaShow(exp.getFormulaShow());
						e.setOrder(exp.getOrder());
						handleResult(cell);
					}
				}
			}
		}
	}

	protected abstract void handleResult(Cell cell);

	/**
	 * 转换行表达式为单元格表达式eg:1行=2行+3行->1_1=2_1+3_1
	 * @param cell
	 */
	public void handleRowExp(Cell cell) {
		convertExpToCellExp(cell, IType.TABLE_INNER_ROW);
	}

	/**
	 * 转换列表达式为单元格表达式eg:1列=2列+3列->1_1=1_2+1_3
	 * @param cell
	 */
	public void handleColExp(Cell cell) {
		convertExpToCellExp(cell, IType.TABLE_INNER_COL);
	}

	/**
	 * 
	 * @param cell
	 */
	public void handleCellExp(Cell cell) {
		convertExpToCellExp(cell, IType.TABLE_INNER_CELL);
	}

	/**
	 * 去掉后缀获取数字eg:1行->1;2列->2
	 * @param str
	 * @return
	 */
	private String getNumber(String str) {
		if (str.endsWith(ReportConstant.ROW_ZH_CN) || str.endsWith(ReportConstant.COL_ZH_CN)) {
			return str.substring(0, str.length() - 1);
		}
		return str;
	}

	public void setExpMap(Map<String, List<Exp>> expMap) {
		this.expMap = expMap;
	}

	public void destory() {
		if (expMap != null) {
			expMap.clear();
			expMap = null;
		}
	}

	private void convertExpToCellExpValidation(Cell cell, String type) {
		List<Exp> exps = expMap.get(type);
		if (exps != null && exps.size() > 0) {
			for (Exp exp : exps) {
				String formula = exp.getFormula();
				// 存储原表达式
				cell.setOldExp(formula);
				// 按关系运算符(><=)拆分
				String[] array = formula.split(ReportConstant.OPERATOR_RELA);
				// 判断计算表达式拆分完成后是否为2部分
				if (array.length == 2) {
					// 等号前面部分为计算指标的行号或列号
					String resultNum = getNumber(array[0]);
					// 等号后面部分为参加计算的指标表达式
					String calcExp = array[1];
					// 按算数运算符(+-*/)拆分
					String[] calcNums = calcExp.split(ReportConstant.OPERATOR_ARITH);
					// 如果计算类型为行计算且指标的行号等于计算指标的行号,那么遍历并替换行表达式为单元格表达式
					if (IType.TABLE_INNER_ROW.equals(type) && cell.getRelRowNum() != null
							&& cell.getRelRowNum().toString().equals(resultNum)) {
						for (String calcNum : calcNums) {
							// 替换成:[行号+拆分符+列号]
							StringBuilder key = new StringBuilder();
							key.append("[").append(getNumber(calcNum)).append(ReportConstant.SPLIT_OPERATOR)
									.append(cell.getRelColNum()).append("]");
							calcExp = calcExp.replaceFirst(calcNum, key.toString());
						}
					}
					// 如果计算类型为列计算且指标的列号等于计算指标的列号,那么遍历并替换列表达式为单元格表达式
					else if (IType.TABLE_INNER_COL.equals(type) && cell.getRelColNum() != null
							&& cell.getRelColNum().toString().equals(resultNum)) {
						for (String calcNum : calcNums) {
							StringBuilder key = new StringBuilder();
							key.append("[").append(cell.getRelRowNum()).append(ReportConstant.SPLIT_OPERATOR)
									.append(getNumber(calcNum)).append("]");
							calcExp = calcExp.replaceFirst(calcNum, key.toString());
						}
					}
					// 如果计算类型为单元格计算且指标的行号与列号等于计算指标的行号与列号,那么不做处理
					else if (IType.TABLE_INNER_CELL.equals(type) && array[0].equals(
							"[" + cell.getAbsRowNum() + ReportConstant.SPLIT_OPERATOR + cell.getAbsColNum() + "]")) {
					} else {
						calcExp = null;
					}
					if (calcExp != null) {
						Exp e = cell.getCalcExp();
						e.setCellExp(calcExp);
						e.setFormulaType(exp.getFormulaType());
						e.setFormulaShow(exp.getFormulaShow());
						e.setOrder(exp.getOrder());
						handleResult(cell);
					}
				}
			}
		}
	}

	/**
	 * 转换行表达式为单元格表达式eg:1行=2行+3行->1_1=2_1+3_1
	 * @param cell
	 */
	public void handleRowExpValidation(Cell cell) {
		convertExpToCellExpValidation(cell, IType.TABLE_INNER_ROW);
	}

	/**
	 * 转换列表达式为单元格表达式eg:1列=2列+3列->1_1=1_2+1_3
	 * @param cell
	 */
	public void handleColExpValidation(Cell cell) {
		convertExpToCellExpValidation(cell, IType.TABLE_INNER_COL);
	}

	/**
	 * 
	 * @param cell
	 */
	public void handleCellExpValidation(Cell cell) {
		convertExpToCellExpValidation(cell, IType.TABLE_INNER_CELL);
	}
}
